package repository

import (
	"errors"
	"gluenet/internal/glue-srvp/adapter/repository/helm"
	"gluenet/internal/glue-srvp/adapter/repository/mysql"
	"gluenet/internal/glue-srvp/domain/dependency"
	"gluenet/internal/glue-srvp/domain/entity"
	"gluenet/internal/pkg/infra"
	"gluenet/internal/pkg/infra/prepare"
)

func init() {
	prepare.RegisterRepo(func() {
		repo := NewConfigMetaRepo()
		prepare.InjectDependency(func() dependency.ConfigMetaRepo {
			return repo
		})
	})
}

func NewConfigMetaRepo() *ConfigMeta {
	r := &ConfigMeta{}
	return r
}

// Meta 是对domain/dependency的MetaRepo的一个实现，具体函数功能请参见接口定义
type ConfigMeta struct {
	Meta
}

func (c ConfigMeta) AddConfig(obj *entity.Config, auth infra.AuthInfo) error {
	var (
		err error
	)

	if obj.ConfigFile.IsUploads {
		info, err := helm.DB.SaveCharts(obj.ConfigFile.UserId, obj.ConfigFile.FileName, obj.ConfigFile.Reader)
		if err != nil {
			return err
		}
		obj.Name = info.Name
		obj.Describe = info.Describe
		obj.Version = "1"
		obj.Kind = infra.ConfigKindHelmChart
		obj.DetailRepoValue.Charts = info.Detail
		obj.DetailRepoValue.OptionJaeger = infra.Enable
		obj.DetailRepoValue.OptionLinkerd = infra.Enable
	}

	session := mysql.DB.NewSession()
	defer session.Close()
	if err = session.Begin(); err != nil {
		return err
	}

	if _, err = session.InsertOne(obj); err != nil {
		session.Rollback()
		return err
	}

	obj.ConfigToUser.UserId = auth.UserId
	obj.ConfigToUser.ConfigId = obj.Id
	obj.ConfigToUser.GroupId = auth.GroupId
	if _, err = session.InsertOne(obj.ConfigToUser); err != nil {
		session.Rollback()
		return err
	}

	if err = session.Commit(); err != nil {
		session.Rollback()
		return err
	}
	return nil
}

func (c ConfigMeta) DelConfig(obj *entity.Config, auth infra.AuthInfo) error {
	var (
		err error
	)

	obj.ConfigToUser.ConfigId = obj.Id
	switch auth.AuthLevel {
	case 0:
	case 1:
		obj.ConfigToUser.GroupId = auth.GroupId
	case 2:
		obj.ConfigToUser.UserId = auth.UserId
		obj.ConfigToUser.GroupId = auth.GroupId
	}

	session := mysql.DB.NewSession()
	defer session.Close()

	if err = session.Begin(); err != nil {
		return err
	}

	affect, err := session.Delete(obj.ConfigToUser)
	if err != nil {
		session.Rollback()
		return err
	}
	if affect == 0 {
		return errors.New("affect row: 0")
	}
	if _, err = session.ID(obj.Id).Delete(obj); err != nil {
		session.Rollback()
		return err
	}

	if err = session.Commit(); err != nil {
		session.Rollback()
		return err
	}

	return nil
}

func (c ConfigMeta) UptConfig(obj *entity.Config, auth infra.AuthInfo) error {
	var (
		ok     bool
		affect int64
		err    error
	)

	obj.ConfigToUser.ConfigId = obj.Id
	switch auth.AuthLevel {
	case 0:
	case 1:
		obj.ConfigToUser.GroupId = auth.GroupId
	case 2:
		obj.ConfigToUser.UserId = auth.UserId
		obj.ConfigToUser.GroupId = auth.GroupId
	}

	session := mysql.DB.NewSession()
	defer session.Close()

	if err = session.Begin(); err != nil {
		return err
	}

	if ok, err = session.Get(&obj.ConfigToUser); err != nil {
		session.Rollback()
		return err
	}
	if !ok {
		session.Rollback()
		return infra.AuthFailed
	}

	if affect, err = session.ID(obj.Id).Update(obj); !ok {
		session.Rollback()
		return err
	}

	if err = session.Commit(); err != nil {
		session.Rollback()
		return err
	}

	if affect == 0 {
		return errors.New("affect row: 0")
	}

	return nil
}

func (c ConfigMeta) FindConfig(objs *[]entity.Config, auth infra.AuthInfo, query interface{}, args ...interface{}) error {
	var (
		join        = "INNER"
		table       = "srvp_config"
		tableToUser = "srvp_config_to_user"
		condition   = "srvp_config.id=srvp_config_to_user.config_id"
	)

	switch auth.AuthLevel {
	case 2:
		return mysql.DB.Select(table+".*").Join(join, tableToUser, condition).
			Where("user_id=? and group_id=?", auth.UserId, auth.GroupId).Where(query, args).Find(objs)
	case 1:
		return mysql.DB.Select(table+".*").Join(join, tableToUser, condition).
			Where("group_id=?", auth.GroupId).Where(query, args).Find(objs)
	case 0:
		return mysql.DB.Where(query, args).Find(objs)
	default:
		return nil
	}
}
